﻿#include "crossplat_def.h"
#include "frame_shmem.h"
#ifndef _WIN32
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#endif // _WIN32
#include "cross_com.h"
#include <string.h>
#define MAX_CLIENT_NUM 8
const uint32_t CFrame_sharemem::FRAME_HEADLEN = 128;
static const int FRAME_H_LEN = BASE_FRAME_HEAD_LEN;
CFrame_sharemem::CFrame_sharemem()
{
    m_buf = NULL;
    m_shmSize = 0;
    m_bOpened = false;
	m_pInfo = NULL;
	m_clientIdx = 0;
    memset(&m_frmHead, 0, BASE_FRAME_HEAD_LEN);
    m_frmHead.frameTag = RDFrameTag;
    m_frmHead.headLen = BASE_FRAME_HEAD_LEN;
    m_frmHead.frameRate = 25;
}

int CFrame_sharemem::Open(const char * shmName,int ch, int bufSize, bool is_producer, char * clientName)
{
    strcpy(m_shmName, shmName);
	//sprintf(shmName, "User%02dCH%02d", userID, ch);
    int user_info_len = sizeof(SHARE_BUF_INFO)* MAX_CLIENT_NUM;
    int base_frminfo_len = sizeof(CACHE_FRM_INFO) + sizeof(CACHE_FRM_INFO) * 32;
    int infoLen = user_info_len + base_frminfo_len;
	int totalSize = bufSize + infoLen + 128;
    //用户信息--基本帧信息--关键帧索引--音视频缓存--镜像帧头
   

    m_frmHead.channel = ch;
#ifdef _WIN32
    int ret = 0;
    if(is_producer) //生产者
    {
        if(m_bOpened)
        {
            TRACE_ERR("File is opened.\n");
            return ERR_FIFO_OPENED;
        }
        m_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, totalSize, shmName);
        if( INVALID_HANDLE_VALUE == m_hMapFile  )
        {
           TRACE_ERR("Create file fail.Buf Size %d ret %d. \n", bufSize, GetLastError());
            return ERR_FIFO_CREATE;
        }
        m_pShareMem = (unsigned char *)MapViewOfFile(m_hMapFile,
                            FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if( NULL == m_pShareMem)
        {
            CloseHandle(m_hMapFile);
            return ERR_FIFO_CREATE;
        }
        m_pInfoBase = m_pInfo    = (SHARE_BUF_INFO *)m_pShareMem;
        if( NULL == m_pInfo  )
        {
            TRACE_ERR("Create file fail.m_pInfo  is NULL .Buf Size %d ret %d. \n", bufSize, GetLastError());
            return ERR_FIFO_CREATE;
        } 
 
        m_pInfo->m_buf_size = bufSize;
    }
    else
    {
        //Client
        if(m_bOpened)
        {
            TRACE_ERR("shmName %d  CH %d File is opened.\n", shmName, ch);
            return ERR_FIFO_OPENED;
        }

        m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shmName);
        if( NULL == m_hMapFile   )
        {
            TRACE_ERR( "Create file fail.Buf Size %d ret %d. \n", bufSize, ret = GetLastError());
            return ERR_FIFO_CREATE;
        }
        m_pShareMem = (unsigned char *)MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if( NULL == m_pShareMem)
        {
            CloseHandle(m_hMapFile);
            return ERR_FIFO_CREATE;
        }

		m_pInfoBase = (SHARE_BUF_INFO *)m_pShareMem;
        //	DEBUG_INFO(COMMON_LIB,"clientID %d CH %d Frm buf size %d ,data size %d .\n",userID,ch,m_pInfo->m_buf_size,GetDataSize());
     
    }
#else
    char lockFileName[64];
    sprintf( lockFileName, "/tmp/.%s", shmName);
    m_lockFd = open(lockFileName, O_CREAT | O_WRONLY | O_APPEND);
    lock();
    m_pShareMem = (unsigned char *) CreateShm(lockFileName, totalSize);
    if( NULL == m_pShareMem   )
    {
        //	DEBUG_ERROR(COMMON_LIB, "Create share mem fail! shmName %s bufSize %d",shmName,bufSize);
        unlock();
		printf("Open CreateShm fail lockFileName %d   errno %d .\n", lockFileName,errno);
        return ERR_FIFO_CREATE;
    }

	m_pInfo = m_pInfoBase = (SHARE_BUF_INFO *)m_pShareMem;
    if (is_producer)
    {
        memset(m_pInfoBase, 0, infoLen);
    }
   
    if(m_pInfoBase->m_buf_size != bufSize)
    {
       m_pInfoBase->m_buf_size = bufSize;  
        fprintf(stderr,"CFrame_sharemem::Open not init  bufSize %d infoLen %d  ,\n", bufSize,infoLen);
       memset(m_pInfoBase, 0, infoLen);     
    }
	
    unlock();
    
#endif
    m_buf = (unsigned char *)(m_pShareMem + infoLen);
    fprintf(stderr,"CFrame_sharemem::Open start reg_user %s ,\n", clientName);
    m_shmSize = bufSize;
	if (!is_producer)
	{
		int idx = reg_user(clientName);
		if (idx < 0)
		{
			printf("over max client clientName %s ,\n", clientName);
			return ERR_OVER_MAXCLIENT;
		}
		m_clientIdx = idx;
	}
    else
    {
        m_base_frm = (BASE_FRM_INFO*)((char*)m_pInfoBase + user_info_len);
        if (m_base_frm->shmTag != ShareMemFlag)
        {
            memset(m_pInfo, 0, infoLen);   
            m_base_frm->key_idx = 0;
            m_base_frm->max_key_frm = 32;
            m_base_frm->last_tm = 0;
            m_base_frm->shmTag = ShareMemFlag;
        }
        int idx = reg_user(clientName);
    }

    m_accessMode = is_producer;
	if (clientName != NULL)
	{
		m_clientName = clientName;
	}

    m_bOpened    = true;

	printf("CFrameBufShm::Open ok  shmName%s m_clientIdx %d ,\n", shmName, m_clientIdx);
    return 0;
}

int CFrame_sharemem::Close()
{
    lock();
	unreg_user((char*)m_clientName.c_str());
#ifdef _WIN32
    if(m_hMapFile)
    {
        CloseHandle(m_hMapFile);
    }
    m_hMapFile = NULL;
    m_bOpened = false;
#else
    //	shmctl(,IPC_RMID,NULL);
    if(m_pShareMem)
    {
        shmdt( m_pShareMem );
        m_pShareMem = NULL;
    }
    if(m_lockFd != -1)
    {
        close( m_lockFd );
        m_lockFd = -1;
    }
#endif
    unlock();
    return 0;
}

#ifndef _WIN32
int CFrame_sharemem::DestryMemory()
{
    if(m_fd != -1)
    {
        int ret = shmctl(m_fd, IPC_RMID, NULL);
        if(ret < 0)
        {
            TRACE("error %d %s", errno, strerror(errno));
        }
        //m_fd = -1;
    }
    return 0;
}
#endif

CFrame_sharemem::~CFrame_sharemem()
{
    lock();
#ifndef _WIN32
    if( NULL != m_pShareMem)
    {
        shmdt( m_pShareMem );
        m_pShareMem = NULL;
    }
    if(m_lockFd != -1)
    {
        close( m_lockFd );
        m_lockFd = -1;
    }
#endif
    unlock();
}

#ifndef _WIN32
struct flock * CFrame_sharemem::file_lock(short type, short whence)
{
    static struct flock ret;
    ret.l_type = type ;
    ret.l_start = 0;
    ret.l_whence = whence;
    ret.l_len = 0;
    ret.l_pid = getpid();
    return &ret;
}
#endif

int CFrame_sharemem::putFrame(uint8_t *pFrameData, uint32_t frameLen, bool bCover)
{
    if( ( NULL == pFrameData  ) || (frameLen <= 0) )
    {
        return ERR_FIFO_PARAM;
    }
	if (!m_bOpened)
	{
		return FIFO_ERR_NOOPEN;
	}
    uint32_t len = GetFreeSize();
	static int  head_len = 0;

	if (!bCover)
	{
		if (len < frameLen)
		{
			return ERR_FIFO_NOTENOUGH;
		}
	}
	else
	{
		ConsumeBuf(frameLen *2);
	}

    lock();

	if (head_len == 0)
	{
		m_frmTool.Init(pFrameData);
		head_len = m_frmTool.GetFrameHeadLen();
	}


	
    if((len = m_pInfo->m_buf_size - m_pInfo->m_pidx) < frameLen)
    {
		if (0 != head_len)
		{   //拷贝帧标记
			if (len < head_len)
			{
				memcpy(m_buf + m_pInfo->m_pidx, pFrameData, head_len);
			}
			else
			{
				memset(m_buf + m_shmSize, 0, head_len);
			}
		}

        memcpy(m_buf + m_pInfo->m_pidx, pFrameData, len);
        memcpy(m_buf, pFrameData + len, frameLen - len);
    }
    else
    {
        memcpy(m_buf + m_pInfo->m_pidx, pFrameData, frameLen);
    }
    ProductBuf(frameLen);
    unlock();
    return frameLen;
}
#if 1
int CFrame_sharemem::ReadFrame(uint8_t* buf, uint32_t frameLen, int* isKeyFrame)
{
    int data_size = GetDataSize();
    if (data_size < FRAME_H_LEN)
    {
        return ERR_DATA_AREA;
    }

    m_lock.lock();

    int diffOffset = 0;

    RD_FRAME_H* pFrm = (RD_FRAME_H*)(m_buf + m_pInfo->m_cidx);
    bool bFound = false;
    if (RDFrameTag != pFrm->frameTag)
    {
        diffOffset = 1;
        int len = m_shmSize - m_pInfo->m_cidx;
        if (len < FRAME_H_LEN)
        {
            memcpy(m_buf + m_shmSize, m_buf, FRAME_H_LEN - len);
        }
        while (diffOffset + FRAME_H_LEN + m_pInfo->m_cidx < m_shmSize)
        {
            if ((diffOffset + FRAME_H_LEN) >= data_size)
            {
                break;
            }
            pFrm = (RD_FRAME_H*)(m_buf + m_pInfo->m_cidx + diffOffset);
            if (RDFrameTag == pFrm->frameTag)
            {
                bFound = true;
                break;
            }
            else
            {
                diffOffset++;
            }
        }

        if (!bFound)
        {
            ConsumeBuf(diffOffset);
            m_lock.unlock();
            return ERR_DATA_AREA;
        }
        else
        {
            if (0 != diffOffset)
            {
                //if (0 == m_ch)
                //{
                //    //TRACE("consume Frame diffofset %d.\n",diffOffset);
                //}
                ConsumeBuf(diffOffset);
            }
        }
    }

    data_size = GetDataSize();
    uint32_t frame_size = pFrm->dataLen + FRAME_H_LEN;
    if (pFrm->dataLen >= m_shmSize)
    {
        ConsumeBuf(FRAME_H_LEN);
        m_lock.unlock();
        return ERR_DATA_AREA;
    }
    if (frame_size > (uint32_t)data_size)
    {
        m_lock.unlock();
        return ERR_DATA_AREA;
    }
    //if (clientID == 0)
    //{
    //    cidx = m_cidx;
    //    m_readFrameNo = pFrm->frameNo;
    //}
    //else
    //{
    //    cidx = pInfo->consumePos;
    //    m_readFrameNo = pFrm->frameNo;
    //}

    
    uint32_t len = m_shmSize - m_pInfo->m_cidx;
    if (len < frame_size)
    {
        memcpy(buf, m_buf + m_pInfo->m_cidx, len);
        memcpy(buf + len, m_buf, frame_size - len);
    }
    else
    {
        memcpy(buf, m_buf + m_pInfo->m_cidx, frame_size);
    }
    
    if(pFrm->frameType == IFrame)
    {   if(isKeyFrame != NULL)
        {
            *isKeyFrame = 1;
        }
        else
            *isKeyFrame = 0;
    }
  //  m_readFrameNo = pFrm->frameNo;

    ConsumeBuf(frame_size);

    m_lock.unlock();

    return frame_size;
}
#else
int CFrame_sharemem::ReadFrame(uint8_t*pFrameData, uint32_t frameLen, int *isKeyFrame)
{
    int ret = 0;
    uint32_t dataSize = 0;
    uint32_t frameSize = 0;
    int addOffset = 0;
	uchar_t tmpBuf[FRAME_HEADLEN*2] = {0};

    uint32_t len = 0;
    bool findTrue = false;
    int parseLen = 0;
    int checklen = FRAME_HEADLEN + len;
    if (!m_bOpened)
    {
        return FIFO_ERR_NOOPEN;
    }
    m_lock.lock();
    dataSize = GetDataSize();
    if (dataSize < 30<<10 || dataSize <= m_last_frm_sz)
    {
        //保证最少有一个帧头的数据大小
        goto ERR_OUT;
    }

    len = m_shmSize - m_pInfo->m_cidx;
    if(len < FRAME_HEADLEN )
    {

        checklen = FRAME_HEADLEN + len;
		memcpy(tmpBuf, m_buf + m_shmSize - len, len);
		if (m_pInfo->m_pidx > FRAME_HEADLEN){
			memcpy(tmpBuf+len, m_buf, FRAME_HEADLEN);
		}else{
			memcpy(tmpBuf+len, m_buf, m_pInfo->m_pidx);
			checklen = len + m_pInfo->m_pidx;
		}

		while(parseLen + (int)FRAME_HEADLEN < checklen)
		{
			m_frmTool.Init(tmpBuf + parseLen);
			if( m_frmTool.IsEffect() &&
				m_frmTool.GetFrameLen() < frameLen)
			{
				TRACE_ERR("add offset %d. cidx %d .\n",addOffset,m_pInfo->m_cidx);
				ConsumeBuf(addOffset);
				findTrue = true;
				break;
			}
			addOffset++;
			parseLen++;
		}


		if (m_pInfo->m_pidx > FRAME_HEADLEN)
		{
			if (!findTrue)
			{
				ConsumeBuf(addOffset);
				addOffset = 0;
				while( (FRAME_HEADLEN+addOffset) < m_pInfo->m_pidx )
				{
					m_frmTool.Init(m_buf + m_pInfo->m_cidx + addOffset);
					if(m_frmTool.IsEffect())
					{
						TRACE_ERR("add offset %d. cidx %d .\n",addOffset,m_pInfo->m_cidx);
						ConsumeBuf(addOffset);
						findTrue = true;
						break;
					}
					addOffset++;
				}
			}
		}

		if (!findTrue)
		{
			ConsumeBuf(addOffset);
			goto ERR_OUT;
		}

		frameSize = m_frmTool.GetFrameLen();
        if (frameSize > frameLen)
        {
            m_pInfo->m_dataErr = true;
            TRACE_ERR("1 Buf size is little.frameLen %d \n",frameLen);
            ret = ERR_FIFO_NOTENOUGH;
            goto ERR_OUT;
        }

		dataSize = GetDataSize();
        if(frameSize > dataSize)
        {
            //数据量大于剩余数据
           // DEBUG_INFO(COMMON_LIB,"1 frame size  %d is bigger dataSize %d \n",frameSize,dataSize);
            unlock();
            m_pInfo->m_nextFrmSize = frameSize;
            return ERR_FIFO_NOTENOUGH;
        }
		int hLen = m_shmSize - m_pInfo->m_cidx;
		if (m_pInfo->m_cidx + FRAME_HEADLEN > m_pInfo->m_buf_size )
		{
			memcpy(pFrameData, m_buf + m_pInfo->m_cidx, hLen);
			memcpy(pFrameData + hLen, m_buf, frameSize - hLen);
		}
		else
		{
			memcpy(pFrameData, m_buf + m_pInfo->m_cidx, frameSize);
		}
    }
    else
    {
		tmpBuf[FRAME_HEADLEN*2];
		m_frmTool.Init(m_buf + m_pInfo->m_cidx);
        if(!m_frmTool.IsEffect())
        {
            if (m_pInfo->m_bOverWrite)
            {
                while((m_pInfo->m_cidx + addOffset + FRAME_HEADLEN) < (m_pInfo->m_buf_size ))
                {
					m_frmTool.Init(m_buf + m_pInfo->m_cidx + addOffset);
                    if(m_frmTool.IsEffect())
                    {
                       // DEBUG_INFO(COMMON_LIB,"add offset %d. cidx %d .\n",addOffset,m_pInfo->m_cidx);
                        ConsumeBuf(addOffset);
                        findTrue = true;
                        break;
                    }
                     ++addOffset;
                }

                if(!findTrue)
                {
                    parseLen = 0;
                    checklen = FRAME_HEADLEN*2;
                    memcpy(tmpBuf, m_buf + m_pInfo->m_buf_size - FRAME_HEADLEN, FRAME_HEADLEN);
                    if (m_pInfo->m_pidx > FRAME_HEADLEN){
                        memcpy(tmpBuf+FRAME_HEADLEN, m_buf, FRAME_HEADLEN);
                    }else{
                        memcpy(tmpBuf+FRAME_HEADLEN, m_buf, m_pInfo->m_pidx);
                        checklen = FRAME_HEADLEN + m_pInfo->m_pidx;
                    }

                    while(parseLen + (int)FRAME_HEADLEN < checklen)
                    {
						m_frmTool.Init(tmpBuf + parseLen);
                        if(m_frmTool.IsEffect())
                        {
                            ConsumeBuf(addOffset);
                            findTrue = true;
                            break;
                        }
						addOffset++;
                        parseLen++;
                    }
					if (m_pInfo->m_pidx > FRAME_HEADLEN)
					{
						if (!findTrue)
						{
							ConsumeBuf(addOffset);
							addOffset = 0;
							while( (FRAME_HEADLEN+addOffset) < m_pInfo->m_pidx )
							{
								m_frmTool.Init(m_buf + m_pInfo->m_cidx + addOffset);;
								if(m_frmTool.IsEffect())
								{
								//	DEBUG_INFO(COMMON_LIB,"add offset %d. cidx %d .\n",addOffset,m_pInfo->m_cidx);
									ConsumeBuf(addOffset);
									findTrue = true;
									break;
								}
								addOffset++;
							}
						}
					}
                }
            }
            else
            {
                while( (m_pInfo->m_cidx + addOffset) < (m_pInfo->m_pidx - FRAME_HEADLEN))
                {
					m_frmTool.Init(m_buf + m_pInfo->m_cidx + addOffset);

                    if(m_frmTool.IsEffect())
                    {
                        //DEBUG_INFO(COMMON_LIB,"add offset %d. cidx %d .\n",addOffset,m_pInfo->m_cidx);
                        ConsumeBuf(addOffset);
                        findTrue = true;
                        break;
                    }
                    ++addOffset;
                }
            }

            if(findTrue)
            {
                dataSize -= addOffset;
            }
            else
            {
                m_pInfo->m_dataErr = true;
                ConsumeBuf(addOffset);
                TRACE_ERR("shm %s 3 Fs Frame data error.", m_shmName);
                ret = ERR_FIFO_PARAM;
                goto ERR_OUT;
            }
        }

		frameSize = m_frmTool.GetFrameLen();
        if (frameSize > frameLen)//
        {
            m_pInfo->m_dataErr = true;
          //  DEBUG_INFO(COMMON_LIB,"2 Buf size is little.frameLen %d \n",frameSize);
            ret = ERR_FIFO_PARAM;
            goto ERR_OUT;
        }
        //检查数据是否超过数据大小
		dataSize = GetDataSize();
        if(frameSize > dataSize)
        {
            m_pInfo->m_nextFrmSize = frameSize;
            ret = ERR_FIFO_NOTENOUGH;
      //      DEBUG_INFO(COMMON_LIB,"2 Frame size %d. Frame Type %c  dataSize %d ret %d \n",
	  //			        frameSize,pFrmHead->frameType,dataSize,ret);
#ifndef _WIN32
			PrintTimeMs(m_frmTool.GetFrameTime(), 0, "Frame time");
#endif
            goto ERR_OUT;
        }

        len = m_shmSize - m_pInfo->m_cidx;
        if(len < frameSize) //again
        {
            memcpy(pFrameData, m_buf + m_pInfo->m_cidx, len);
            memcpy(pFrameData + len, m_buf, frameSize - len);
        }
        else
        {
            //The best 最理想的情况．
            memcpy(pFrameData, m_buf + m_pInfo->m_cidx, frameSize);
        }
    }

    m_pInfo->m_nextFrmTime = m_frmTool.GetFrameTime();
    ConsumeBuf(frameSize);
    m_frmTool.Init(m_buf + m_pInfo->m_cidx);
    if (!m_frmTool.IsEffect())
    {
        assert(false);
    }
    m_lock.unlock();
    return frameSize;
ERR_OUT:
    m_lock.unlock();
    return ret;
}
#endif
//
//思路 
/*
  从最新的I帧反向推预录像的时间，找到I帧
  预录像5秒
 A 例如 1 2 3 4 5 6 7 8 9 10 
  从10 个帧开始，向前推5个帧，相当于定位完成后，从6个帧开始获取新的数据
 B  1 2 3 4 5
  如果不足5秒，找到就直接首个I帧开始
 
*/

int CFrame_sharemem::SeekTime(int64_t cur_ms, int pre_sec)
{

	//统计有多少个I帧


	return 0;
}

void CFrame_sharemem::lock()
{
    //pthread_mutex_lock( mMutex );
#ifdef _WIN32
  // m_lock.Lock();
#else
    if( -1 != m_lockFd &&fcntl( m_lockFd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET) ) == -1 )
    {
        //	DEBUG_API_ERROR(COMMON_LIB, "fcntl(lock)");
        TRACE_ERR("lock error.lockFd %d \n", m_lockFd);
    }
#endif
}

void CFrame_sharemem::unlock()
{
#ifdef _WIN32
  //  m_lock.UnLock();
#else
    if(-1 != m_lockFd && fcntl( m_lockFd, F_SETLKW, file_lock(F_UNLCK, SEEK_SET) ) == -1 )
    {
        //	DEBUG_API_ERROR(COMMON_LIB, "fcntl(unlock)");
       TRACE_ERR("Unlock error.lockFd %d \n", m_lockFd);
    }
#endif
}

void *CFrame_sharemem::CreateShm(const char *name, int size)
{
    void *pShareMem = NULL;
    if( ( NULL == name  ) || (size <= 0) )
    {
        return NULL;
    }
	printf("CFrame_sharemem::CreateShm  %s size %d.\n", name, size);
    int fd = 0;
#ifdef _WIN32
#else
    if ( (fd = open( name, O_RDWR | O_CREAT | O_EXCL) ) > 0 )
    {
        close( fd );
    }
    key_t key;
    key = ftok(name, 'a');
	if (key == -1)
	{
		fprintf(stderr, "Creat name %s Key Error：%s\a\n", name,strerror(errno));
	}
    m_fd = shmget( key, size, IPC_CREAT );
    pShareMem = shmat( m_fd, NULL, 0 );
    if( pShareMem == (void *) - 1 )
    {
        //DEBUG_API_ERROR(COMMON_LIB, "shmat()");
		printf("CFrameBufShm::CreateShm fail %s errno %d key %d .\n", name,errno, key);
        return NULL;
    }
    struct shmid_ds shmIdDes;
    shmctl( m_fd, IPC_STAT, &shmIdDes );
    if( 1 == shmIdDes.shm_nattch  )
    {
        memset( pShareMem, 0, size );
    }
#endif
    return pShareMem;
}

void CFrame_sharemem::reset()
{
    lock();

	m_pInfoBase->m_pidx = 0;
	m_pInfoBase->m_cidx = 0;		//产生的数据量
    unlock();
}

int CFrame_sharemem::read(unsigned char *buf, uint32_t size, bool bPeek)
{
    if(0 == size || NULL == buf)
    {
        return ERR_FIFO_PARAM;
    }
    if (GetDataSize() < size) // 缓存数据长度不足
    {
        return ERR_FIFO_NOTENOUGH;
    }
    lock();
    uint32_t len =  m_shmSize -  m_pInfo->m_cidx;
    if(len < size)
    {
        memcpy(buf, m_buf + m_pInfo->m_cidx, len);
        memcpy(buf + len, m_buf, size - len);
    }
    else
    {
        memcpy(buf, m_buf + m_pInfo->m_cidx, size);
    }
    if(0 == bPeek)
    {
        ConsumeBuf(size);
    }
    unlock();
    return size;
}



int CFrame_sharemem::ConsumeBuf(uint32_t size)
{
    lock();
    m_pInfo->m_cidx += size;
    if(m_pInfo->m_cidx > m_shmSize )
    {
        m_pInfo->m_cidx = m_pInfo->m_cidx % m_shmSize;
    }
    unlock();
    return 0;
}


int CFrame_sharemem::ProductBuf(uint32_t size)
{
    lock();
    m_pInfo->m_pidx += size;
    if(m_pInfo->m_pidx >= m_shmSize)
    {
        m_pInfo->m_pidx = m_pInfo->m_pidx % m_shmSize;
    }
    unlock();
    return 0;
}

int CFrame_sharemem::ProducEmptyFrm(uint32_t size)
{
    lock();
    m_pInfo->m_pidx += size;
    if(m_pInfo->m_pidx >= m_shmSize)
    {
        m_pInfo->m_pidx = m_pInfo->m_pidx % m_shmSize;
    }
    unlock();
    return 0;
}

//镜像一帧头，便于找到有效数据
int CFrame_sharemem::MirrorFrameHead()
{
	lock();
	memcpy(m_buf+ m_shmSize,m_buf,FRAME_HEADLEN);
	unlock();
	return 0;
}
unsigned char *CFrame_sharemem::GetBufOffset(uint32_t size, uint32_t *leaf_size, unsigned char **tail_buf)
{
    if (0 == size)
    {
        return NULL;
    }
    lock();
    uint32_t len = m_shmSize - m_pInfo->m_cidx;
    if(len < size)
    {
        *leaf_size = len;		 
        *tail_buf = m_buf + m_pInfo->m_cidx;
        unlock();
        return m_buf;
    }
    else
    {
        *leaf_size = 0;
        tail_buf = NULL;
        unlock();
        return m_buf + m_pInfo->m_cidx;
    }
}

uint32_t CFrame_sharemem::GetDataSize()
{
    uint32_t data_size = 0;
	if (m_pInfo == NULL)
	{
		return 0;
	}


    data_size = (m_pInfoBase->m_pidx + m_shmSize - m_pInfo->m_cidx) % m_shmSize;

    return data_size;
}



int CFrame_sharemem::write(unsigned char *buf, uint32_t size)
{
    uint32_t len = GetFreeSize();
    if (0 == len || size > len ) // 缓存数据长度不足
    {
        return ERR_FIFO_NOTENOUGH;
    }
    lock();
    if((len = m_shmSize - m_pInfoBase->m_pidx) < size)
    {
        memcpy(m_buf + m_pInfoBase->m_pidx, buf, len);
        memcpy(m_buf, buf + len, size - len);
    }
    else
    {
        memcpy(m_buf + m_pInfoBase->m_pidx, buf, size);
    }
    ProductBuf(size);
    unlock();
    return size;
}

unsigned char *CFrame_sharemem::GetFreeBuf(unsigned char **tail_buf, uint32_t *leaf_size)
{
    lock();

    if(m_pInfoBase->m_pidx < m_pInfo->m_cidx )
    {
        *leaf_size = 0;
        tail_buf = NULL;
        unlock();
        return m_buf + m_pInfoBase->m_pidx;
    }
    else
    {
        *leaf_size = m_shmSize - m_pInfoBase->m_pidx;
        *tail_buf = m_buf;
        unlock();;
        return m_buf + m_pInfoBase->m_pidx;
    }
}

int CFrame_sharemem::reg_user(char* userName)
{
	int idx = 0;
	bool bReg = false;
	//首个用户
	for (idx = 0; idx < MAX_CLIENT_NUM; idx++)
	{
		//no use
		if (0 == strlen(m_pInfoBase[idx].clientName))
		{
			strcpy(m_pInfoBase[idx].clientName, userName);
			bReg = true;
			m_pInfo = &m_pInfoBase[idx];
			break;
		}
	}

	if (!bReg)
	{
		return -1;
	}
	return idx;
}

int CFrame_sharemem::unreg_user(char* userName)
{
	int idx = 0;
	bool bUnReg = false;
	//首个用户
	for (idx = 0; idx < MAX_CLIENT_NUM; idx++)
	{
		//no use
		if (0 == strcmp(m_pInfoBase[idx].clientName, userName))
		{
			memset(m_pInfoBase[idx].clientName,0, 12);
			bUnReg = true;
			break;
		}
	}

	if (!bUnReg)
	{
		return -1;
	}
	return idx;
}

int CFrame_sharemem::read_buf(uint32_t offset, unsigned char *buf, uint32_t size, bool bConsume)
{
    if(offset > m_shmSize)
    {
        TRACE_ERR( "Requiry over data. offset %d size %d \n", offset, size);
        return ERR_FIFO_OVERDATA;
    }
    lock();
    if((offset + size) <= m_shmSize)
    {
        memcpy(buf, m_buf + offset, size);
    }
    else
    {
        int part_size1 = m_shmSize - offset + 1;
        memcpy(buf, m_buf + offset, part_size1);
        memcpy(buf + part_size1, m_buf, (size - part_size1));
    }
    if(bConsume)
    {
        ConsumeBuf(size);
    }
    unlock();
    return 0;
}

int CFrame_sharemem::WriteFrame(uint8_t* buf, uint32_t size, int frameType, int64_t pts , int codeType)
{
    int ret = 0;
    uint32_t len = GetFreeSize();
    uint32_t data_sz = FRAME_H_LEN + size;

    if (NULL == m_buf)
    {
        return ERR_FILE_OPEN;
    }

    if (size == 0)
    {
        return ERR_DATA_SIZE;
    }
    m_lock.lock();
    //获取时间
    int64_t msec = 0;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    msec = (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000;

    //CROSS_ASSERT(msec >= m_lastTime);

    m_frmHead.frameType = frameType;
    if (pts != 0)
    {
        m_frmHead.pts = pts;
    }
    else
    {
        m_frmHead.pts = msec;
    }

    m_frmHead.dataLen = size;
    m_frmHead.codec_type = codeType;

    if ((uint8_t)frameType != AFrame)
    {
        m_frmHead.frameNo = m_frameNo++;
    }

    //写入帧头信息
    CACHE_FRM_INFO* cacheInfo = (CACHE_FRM_INFO *) ((char*)m_base_frm + sizeof(BASE_FRM_INFO) + sizeof(CACHE_FRM_INFO) * m_base_frm->key_idx);
    if ((uint8_t)frameType == IFrame)
    {
        cacheInfo->len = data_sz;
        cacheInfo->frameType = frameType;
        cacheInfo->pos = m_pInfoBase->m_pidx;
        cacheInfo->frmNo = m_frmHead.frameNo;
        cacheInfo->time = m_frmHead.pts;
    }

    //写入数据区信息
    int buf_pos = 0;
    len = m_shmSize - m_pInfoBase->m_pidx;
    if (len < (uint32_t)data_sz)
    {
        if (len < (uint32_t)FRAME_H_LEN)
        {
            //拷贝帧头
            //实际内存已经多分配了一个帧头信息，所以这里不会导致越界
            memcpy(m_buf + m_pInfoBase->m_pidx, &m_frmHead, FRAME_H_LEN);
            memcpy(m_buf, (uchar_t*)&m_frmHead + len, FRAME_H_LEN - len);//尾部镜像技术

            buf_pos = FRAME_H_LEN - len;
            //拷贝数据
            memcpy(m_buf + buf_pos, buf, size);
        }
        else
        {//拷贝帧头
            memcpy(m_buf + m_pInfoBase->m_pidx, &m_frmHead, FRAME_H_LEN);
            //数据分成两段
            len = len - FRAME_H_LEN;
            if (0 != len)
            {
                memcpy(m_buf + m_pInfoBase->m_pidx + FRAME_H_LEN, buf, len);
            }
            CROSS_ASSERT(size > len);
            memcpy(m_buf, buf + len, size - len);
        }
    }
    else
    {
        // CROSS_ASSERT(m_pidx < m_buf_size);
        memcpy(m_buf + m_pInfoBase->m_pidx, &m_frmHead, FRAME_H_LEN);
        memcpy(m_buf + m_pInfoBase->m_pidx + FRAME_H_LEN, buf, size);
    }

    m_pInfoBase->m_pidx += data_sz;
    if (m_pInfoBase->m_pidx >= m_shmSize)
    {
        m_pInfoBase->m_pidx = m_pInfoBase->m_pidx % m_shmSize;
    }

    m_base_frm->last_tm = m_frmHead.pts;
    if (m_base_frm->max_key_frm == 0)
    {
        m_base_frm->max_key_frm = 32;
    }
    m_base_frm->key_idx  = (m_base_frm->key_idx+1) % m_base_frm->max_key_frm;
    
    m_last_frm_sz = size;
    m_lock.unlock();
    return ret;
}
